#ifndef __TIMER_HPP__
#define __TIMER_HPP__

#include "table.hpp"
#include <sys/time.h>

using namespace std;

class TimerNode
{
  friend class Timer;
  friend class TimerUnit;

private:
  static int nodeCount;

  void (*func)(void *);
  void * obj;
  bool active;
  bool reset;
  bool done;
  unsigned int procTick ;
  unsigned int nextTick ;
  bool mark;

  void proc ();
  void attach (TimerNode * node);
  void detach ();
  TimerNode * getNext (void) { return this->next; }
  static int getNodeCount () { return nodeCount; }
  static void * operator new (size_t size);
  static void operator delete (void * obj, size_t size);

  // for test
  void marking () { this->mark = true; }

public:
  TimerNode * next, * prev;

  TimerNode () : func (NULL), obj (NULL), 
		 active (false), reset (false), done (false), procTick (0), nextTick (0),
		 mark (false), next (this), prev (this)
  {
    assert (nodeCount >= 0); 
    nodeCount++; 
  }
  ~TimerNode ()
  {
    if (this->next && this->prev)
      this->detach ();
    
    nodeCount--;
    assert (nodeCount >= 0);
  }

  void setProc (void (*func)(void *), void * obj);
  bool isActive () { return this->active; }
  void enable ();
  void disable ();
};

class Timer;

class TimerUnit
{  
  friend class Timer;

private:
  static int unitCount;
  Timer * timer;
  unsigned int procTick;
  TimerNode root;
  static const bool DEBUG = false;

public:

  TimerUnit () : timer (NULL), procTick (0)
  {
    this->root.next = &this->root;
    this->root.prev = &this->root;    
    unitCount++;
  }
  ~TimerUnit ()
  {
    TimerNode * node, * next;
    for (node = this->root.next; node != &(this->root); node = next)
      {
	next = node->next;
	delete node;
      }

    unitCount--;
  }

  void releaseNode ();
  static int getUnitCount () { return unitCount; }  
};

class Timer 
{
  friend class TimerUnit;

private:
  unsigned int span; /* msec */
  unsigned int size; /* array size */
  unsigned int tick; /* current tick */
  struct timeval tv;
  bool running;
  PTree<TimerUnit> * unit ;

  static const bool DEBUG = false;

  TimerUnit * fetchTimerUnit (unsigned int tick);
  TimerUnit * lookupTimerUnit (unsigned int tick);
  void removeTimerUnit (unsigned int tick);
  void attachTimerNode (TimerNode * node, unsigned int tick);

public:
  Timer (int size = 3600, int span = 100) :
    span (span), size (size), tick (0), running (false)
  {
    this->unit = new PTree<TimerUnit> [size];
    memset (&tv, 0, sizeof (tv));
  };
  ~Timer ()
  {
    delete [] this->unit;
  };

  void proc (void);
  void proc (struct timeval * tv);
  TimerNode * setTimer (void (*func)(void *), void * obj, int tick);
  void resetTimer (TimerNode * tnode, int tick);
};


#endif /* __TIMER_HPP__ */
